package com.qfedu.aunt.commons.auth.filter;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.qfedu.aunt.commons.auth.security.TokenManager;
import com.qfedu.aunt.commons.exception.BusinessException;
import com.qfedu.aunt.commons.manager.RedisManager;
import com.qfedu.aunt.commons.result.R;
import com.qfedu.aunt.commons.result.ResponseCode;
import com.qfedu.aunt.commons.utils.UserInfoContainer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 用户登陆成功之后 访问其他方法的时候 需要进行用户的身份校验
 * 下面这个过滤器就是进行身份校验和授权的
 *
 * 所谓的授权 就是从数据库中找到用户的权限信息 并设置给Security方便进行鉴权
 */
@Slf4j
public class TokenAuthFilter extends BasicAuthenticationFilter {

    private TokenManager tokenManager;

    private RedisManager redisManager;

    public TokenAuthFilter(AuthenticationManager authenticationManager,TokenManager tokenManager,RedisManager redisManager) {
        super(authenticationManager);
        this.tokenManager = tokenManager;
        this.redisManager=redisManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //这里获取前端请求的路径判断是不是登陆
//        String requestURI = request.getRequestURI();
//        if("/user/login".equals(requestURI)){
//            //说明这个地址是不需要拦截的
//            chain.doFilter(request,response);
//            return;
//        }

        /**
         * 首先从前端传递过来的token中获取我们的权限信息
         */
        UsernamePasswordAuthenticationToken authRequest = getAuthentication(request);
        //判断如果有权限信息，放到权限上下文中;
        if(authRequest != null) {
            SecurityContextHolder.getContext().setAuthentication(authRequest);
            chain.doFilter(request,response);
            return;
        }

        //这里如果等于空那么就应该告诉他没有权限

        R error = R.error(ResponseCode.AUTHTICATION_EXCEPTION.getCode(),
                ResponseCode.AUTHTICATION_EXCEPTION.getMessage());
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write(JSON.toJSONString(error));
        response.getWriter().flush();
        response.getWriter().close();
        return;
    }

    /**
     * 通过前端传递过来的token从而来获取我们的权限列表信息
     * @param request
     * @return
     */
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        //从header获取token
        String token = request.getHeader("token");

        if(token != null) {

            String username="";
            try {
                //这里需要获取用户名信息
                username = tokenManager.getUserNameFromToken(token);
            }catch (Exception err){
                return null;
            }
            //从本地的Map中获取我们的权限列表信息
            //List<String> permissionValueList = UserInfoContainer.getPermsByToken(token);
            //这里要从Redis中获取我们的权限信息
            String permJsonString = (String) redisManager.getString(token);
            //接下来就要将这个数据转换成String类型的集合
            if(StringUtils.isEmpty(permJsonString)){
                //说明用户没带token
                return null;
            }
            //接下来就应该转换成List集合
            List<String> permissionValueList = JSON.parseArray(permJsonString, String.class);
            //接下来就是获取数据放到认证的上下文中
            Collection<GrantedAuthority> authority = new ArrayList<>();
            if(null!=permissionValueList&&permissionValueList.size()!=0){
                for(String permissionValue : permissionValueList) {
                    SimpleGrantedAuthority auth = new SimpleGrantedAuthority(permissionValue);
                    authority.add(auth);
                }
            }
            return new UsernamePasswordAuthenticationToken(username,token,authority);
        }
        return null;
    }

}
